import { PUBLICTERMS } from "./publicTerms.js";
// import ShortcutKey from "./ShortcutKey";
const recursionValidate = function (list, validateResultSet) {
    // debugger;
    validateResultSet = validateResultSet || { successful: true, message: "通过", resultSet: [] };

    _.each(list, (validateWidget) => {
        let instanceCode = _.get(validateWidget, "options.instanceCode");
        let vueInstance = _.get(window, `Widget.${instanceCode}`);
        if (vueInstance && vueInstance.Validate && true !== vueInstance.skipValidate) {
            let validateStatus = vueInstance.Validate(validateResultSet);
            if (validateResultSet.successful) {
                validateResultSet.successful = validateStatus.successful;
                validateResultSet.message = validateStatus.message;
            }
            if (validateWidget.tabPanel) {
                // debugger;
                // Widget.fm_legacy_tabs.$set(Widget.fm_legacy_tabs.element.tabs[0],'hasError',true)
                // vueInstance.$set(vueInstance.tabPanel, 'hasError', !validateResultSet.successful);
                let hasError = validateWidget.tabPanel.hasError || !validateStatus.successful;
                vueInstance.$set(validateWidget.tabPanel, 'hasError', hasError);
                let falseCount = validateWidget.tabPanel.hasErrorCount || 0;
                let hasErrorWidgets = validateWidget.tabPanel.hasErrorWidgets || [];
                _.map(validateStatus.resultSet || [validateStatus], item => {
                    if (item.successful === false) {
                        // debugger;
                        if (item.targetWidget) {
                            item.targetWidget.inTabPanel = validateWidget.tabPanel;
                            hasErrorWidgets.push(validateWidget.InstanceCode);
                        }
                        falseCount += 1;
                    }
                });
                vueInstance.$set(validateWidget.tabPanel, 'hasErrorCount', falseCount);
                vueInstance.$set(validateWidget.tabPanel, 'hasErrorWidgets', hasErrorWidgets);
            }
            if (validateStatus.resultSet) {
                _.each(validateStatus.resultSet, eachItem => {
                    validateResultSet.resultSet.push(eachItem);
                })
            } else {
                validateResultSet.resultSet.push(validateStatus);
            }
        }
    });
    return validateResultSet;
}

const recursionSetReadOnly = function (list, readOnly) {
    _.each(list, (validateWidget) => {
        let instanceCode = _.get(validateWidget, "options.instanceCode");
        let vueInstance = _.get(window, `Widget.${instanceCode}`);

        if (vueInstance && vueInstance.SetReadOnly) {
            vueInstance.SetReadOnly(readOnly);
        }
        if (vueInstance && _.has(vueInstance, 'ReadOnly')) {
            vueInstance.ReadOnly = readOnly;
        }
        if (vueInstance && vueInstance.options) {
            // 2023年12月22日 通过Widget.Root.SetReadOnly(true)时清空placeholder
            if (readOnly) {
                vueInstance.options.placeholder = ""
            } else {
                vueInstance.options.placeholder = vueInstance._originalOpts.placeholder
            }
        }
    });
}

const clearValidate = function (list, validateResultSet) {
    debugger;
    _.each(list, (validateWidget) => {
        let instanceCode = _.get(validateWidget, "options.instanceCode");
        let vueInstance = _.get(window, `Widget.${instanceCode}`);
        if (vueInstance && vueInstance.ClearValidate) {
            vueInstance.ClearValidate();
        }
    });
}

const getInstanceCode = function () {
    // let opts = _.get(this, "element.options", this.options);
    return "_fas@" + new Date().valueOf();
}
const registerInstance = function () {

    let instance = this;
    if (this.ucContainer) {
        this.ucContainer[this.fasInstanceCode] = instance;
        let wPath = `Widget.${this.ucContainer.InstanceCode}_${this.fasInstanceCode}`;
        delete window.Widget[this.fasInstanceCode];
        // _.set(window, wPath, instance);
    } else {
     
        _.set(window, `Widget.${this.fasInstanceCode}`, instance);
    }
    // _.set(window, `Widget.${this.fasInstanceCode}`, this);
}

export default {
    recursionValidate,
    recursionSetReadOnly,
    clearValidate,

    getInstanceCode,
    registerInstance,
    mixinValidate: {
        data() {
            return {
                fasInstanceCode: this.getInstanceCode(),
                recursionValidate,
            };
        },
        mounted() {
            this.registerInstance();
        },
        computed: {
            fasWidgetList() {
                return _.get(this, 'element.list', []);
            }
        },
        watch: {
            "element.options.instanceCode": {
                handler(val, oldVal) {
                    delete window.Widget[oldVal];
                    window.Widget[val] = this;
                }
            },
        },
        methods: {
            getInstanceCode,
            registerInstance,
            Validate() {
                this.preprocessedValidate && this.preprocessedValidate();
                return recursionValidate(this.fasWidgetList);
            },
            ClearValidate() {
                return clearValidate(this.fasWidgetList);
            },
            SetReadOnly(readOnly) {
                return recursionSetReadOnly(this.fasWidgetList, readOnly);
            }
        }
    }
}

export let mixinValidateRoot = {
    mounted() {
        _.set(window, "Widget.Root", this);
        _.set(window, "Widget.Validate", () => {
            return Widget.Root.Validate();
        });
        _.set(window, "Widget.ClearValidate", () => {
            return Widget.Root.ClearValidate();
        });

        _.set(window, "Widget.ValidateTabs", () => {
            return Widget.Root.ValidateTabs();
        });

        _.set(window, "Widget.ValidateTabsHasError", () => {
            return Widget.Root.ValidateTabsHasError();
        });

        _.set(window, "Widget.ShowLoading", this.ShowLoading);
        _.set(window, "Widget.HideLoading", this.HideLoading);
        _.set(window, "Widget.IsLoading", this.IsLoading);

        _.set(window, "Widget.FireUCEvent", this.FireUCEvent);

        _.set(window, "Widget.ShortcutKey", ShortcutKey);


        let OnKeyDown = pageMetaData.Events.find(item => item.ActionType == 0 && item.Name == "OnKeyDown" && item.JSScript)
        if (OnKeyDown) {
            document.addEventListener('keydown', (event) => {
                new Function("event", OnKeyDown.JSScriptES5)(event)
            })
        }
    },
    methods: {
        Validate() {
            return recursionValidate(this.data.list);
        },
        ClearValidate() {
            return clearValidate(this.data.list);
        },
        ValidateTabsHasError() {
            return this.ValidateTabs({ hasError: true });
        },
        ValidateTabs(opts) {
            let legacyTabs = _.filter(Widget, (item) => {
                return item.element && item.element.Tag == "fm-legacy-tabs";
            });
            _.each(legacyTabs, (tab, index) => {
                if (opts) {
                    if (_.find(tab.VisibleTabs, opts)) {
                        if (tab.Validate) {
                            tab.Validate();
                        }
                    }
                } else {
                    if (tab.Validate) {
                        tab.Validate();
                    }
                }
            });
        },
        ShowLoading() {
            if (window._ShowLoading) window._ShowLoading.apply(window._ShowLoading, arguments);
        },
        HideLoading() {
            if (window._HideLoading) window._HideLoading.apply(window._HideLoading, arguments);
        },
        IsLoading() {
            if (window._IsLoading) return window._IsLoading.apply(window._IsLoading, arguments);
        },
        FireUCEvent: function (eventName, eventArgs) {
            eventArgs = eventArgs || { Data: {}, Event: {} };
            if (!eventArgs.CurrentWidget) {
                let targetWidget = window._fasTriggerEvent;
                if (targetWidget && targetWidget.ucContainer) {
                    eventArgs.CurrentWidget = targetWidget.ucContainer;
                }
            }

            let ucContainer = eventArgs.CurrentWidget;
            if (ucContainer.triggerEvent) {
                ucContainer[eventName + "Args"] = eventArgs;
                ucContainer.triggerEventHandler(eventName, arguments, true);
            }
        }
    }
}

export let mixinReadOnly = {
    methods: {
        SetReadOnly(readOnly) {
            return recursionSetReadOnly(this.data.list, readOnly);
        }
    }
}

export let mixinEvent = {
    methods: {
        findEvent(list, findKey) {
            var returnValue = [];
            _.each(list, (item) => {
                if (item.key == findKey) {
                    returnValue = item.Events;
                    return false;
                } else {
                    if (item.list) {
                        returnValue = this.findEvent(item.list, findKey);
                    }
                }
            });
            return returnValue;
        },
        triggerEvent(eventName, args) {
            // var findKey = this.widget.key;
            // var events = this.findEvent(window.FasFmData.list, findKey);

            var events = this.widget.Events;

            var findEvent = _.find(events || [], (eventItem) => {
                return (
                    eventItem.Name &&
                    eventItem.Name.toLowerCase() == eventName.toLowerCase()
                );
            });
            if (false === eventName.toLowerCase().includes("mouse")) {
                // console.info(
                //   this.options.instanceCode,
                //   eventName,
                //   findEvent ? findEvent : "未绑定"
                // );
            }

            if (findEvent && findEvent.ActionType != -1) {
                if (window.TeldFasRTUtils && window.TeldFasRTUtils.trigger) {
                    window.TeldFasRTUtils.trigger.trigger(findEvent);
                } else {
                    alert("当前环境无法触发事件执行上下文");
                    return;
                }
            }
        },
        triggerEventHandler(eventName, args, immediate) {
            if (immediate) {
                return this.triggerEvent.apply(this, [eventName, ...(args || [])]);
            } else {
                this.$nextTick(() => {
                    return this.triggerEvent.apply(this, [eventName, ...(args || [])]);
                });
            }

        },
        FireEvent(eventName) {
            this.triggerEventHandler(eventName);
        },
    }
}

export let mixinDataSource = {
    methods: {
        initDataSource() {
            // console.log(`this.isDevEnv=${this.isDevEnv}`);
            if (this.hasDataSource()) {
                // debugger;
                if (
                    this.options.dataSource.DataSourceType ==
                    CompConst.DataSourceTypeConst.VARIABLE
                ) {
                    if (_.hasIn(this, "ctrlBindValue")) {
                        this.ctrlBindValue = this.fasBindValue;
                    }
                    if (_.hasIn(this, "dataSource")) {
                        this.dataSource = this.fasBindValue;
                        this.totalCount = this.fasBindValueListCount;
                    }
                } else if (
                    this.options.dataSource.DataSourceType ==
                    CompConst.DataSourceTypeConst.ACTION &&
                    this.options.dataSource.LoadDataTime === false
                ) {
                    this.loadDataFormAction();
                }
            }
        },
        ChangeDataSource(newDsConf) {
            this.options.dataSource = { ...this.options.dataSource, ...newDsConf };
            this.initDataSource();
        },
        reloadDataSource(reload) {
            // debugger;
            //2021年9月14日，让数据的执行等待绑定对象变化响应后执行，
            this.$nextTick(() => {
                if (
                    this.options.dataSource.DataSourceType ==
                    CompConst.DataSourceTypeConst.VARIABLE
                ) {
                    this.loadDataFormVariable(reload);
                } else {
                    this.loadDataFormAction();
                }
            });
        },
        loadDataFormVariable(reload) {
            if (reload && this.hasTeldFasRTUtils() && this.isDevEnv !== true) {
                this.execRefreshVariable(
                    this.options.dataSource.DataSource,
                    this.fasBindContext[this.options.dataSource]
                );
            }
        },
        getActionDataBindWithListDataSource() {
            let splitDataBind = _.get(
                this.options,
                "listDataSource.DataBind",
                ""
            ).split(".");
            return splitDataBind.splice(2).join(".");
        },
        getActionDataBind() {
            let splitDataBind = _.get(this.options, "dataSource.DataBind", "").split(
                "."
            );
            return splitDataBind.splice(2).join(".");
        },
        getActionShema(actionID) {
            /** 2021年9月10日 经讨论不需要进行映射，两绑定的就是别名 */
            if (
                window.TeldFasRTUtils.init &&
                window.TeldFasRTUtils.init.getShemaByActionID
            ) {
                let actionShema = window.TeldFasRTUtils.init.getShemaByActionID(
                    actionID
                ) || {
                    Children: [],
                };
            }
            return actionShema;
        },
        loadDataFormAction() {
            if (_.hasIn(this, "dataSource")) {
                this.loadDataFormActionList();
            } else {
                this.loadDataFormActionRecord();
            }

            /**
             * 
             * 2021年9月10日 经讨论不需要进行映射，两绑定的就是别名
            debugger;
            let dsactionShema = this.getActionShema(
              this.options.dataSource.DataSource
            );
      
            this.dsactionShema = dsactionShema;
             */
        },
        setActionList(data) {
            // debugger;
            let actionBindPath = this.getActionDataBind();
            if (_.has(data, actionBindPath)) {
                this.totalCount = data.Count;
                this.dataSource = _.get(data, actionBindPath);
            } else {
                this.$message({
                    message: `Action 返回类型不符合预期,期望List (检查组件ID:${this.InstanceCode}数据源设置)`,
                    type: "warning",
                });
            }
        },
        loadDataFormActionList() {
            if (this.hasTeldFasRTUtils() && this.isDevEnv !== true) {
                // debugger;
                let actionR = this.execServerAction(
                    this.options.dataSource.ActionType,
                    this.options.dataSource.DataSource,
                    this.options.dataSource.Parameters
                );
                if ((actionR && actionR.then) || _.has(actionR, "Count")) {
                    if (actionR.then) {
                        actionR.then(this.setActionList);
                    } else {
                        this.setActionList(actionR);
                    }
                } else {
                    console.log(`Action 返回类型不符合预期 (检查组件ID:${this.InstanceCode}数据源设置)`);
                    this.$notify({
                        message:PUBLICTERMS.public.checkAction.replace(/\${InstanceCode}/,this.InstanceCode),
                        type: "warning",
                    });
                }
            }
        },
        setActionRecord(data) {
            // debugger;
            let actionBindPath = this.getActionDataBind();
            if (_.has(data, actionBindPath)) {
                this.ctrlBindValue = _.get(data, actionBindPath);
            } else {
                this.$message({
                    message: PUBLICTERMS.public.checkAction.replace(/\${InstanceCode}/,this.InstanceCode),
                    type: "warning",
                });
            }
        },
        loadDataFormActionRecord() {
            // debugger;
            if (this.hasTeldFasRTUtils() && this.isDevEnv !== true) {
                let actionR = this.execServerAction(
                    this.options.dataSource.ActionType,
                    this.options.dataSource.DataSource,
                    this.options.dataSource.Parameters
                );
                if (actionR) {
                    if (actionR.then) {
                        actionR.then(this.setActionRecord);
                    } else {
                        this.setActionRecord(actionR);
                    }
                } else {
                    this.$message({
                        message: PUBLICTERMS.public.checkAction.replace(/\${InstanceCode}/,this.InstanceCode),
                        type: "warning",
                    });
                }
            }
        },

        SetModifyProp(valObj) {
            // debugger;
            let mapping = _.transform(
                this.widget.Properties,
                (result, item) => {
                    result[item.Code] = item.PropType;
                },
                {}
            );
            _.each(valObj, (value, key) => {
                if (_.has(mapping, key)) {
                    if (mapping[key] == 2) {
                        if (_.hasIn(this, key)) {
                            this[key] = value;
                        } else if (_.hasIn(this, _.lowerFirst(key))) {
                            this[_.lowerFirst(key)] = value;
                        }
                    }

                    if (mapping[key] == 3) {
                        if (_.hasIn(this.options, key)) {
                            this.options[key] = value;
                        } else if (_.hasIn(this.options, _.lowerFirst(key))) {
                            this.options[_.lowerFirst(key)] = value;
                        }
                    }
                }
            });
        },
        hasTeldFasRTUtils() {
            return !!window.TeldFasRTUtils;
        },
        execExpression(expression, defaultValue) {
            // debugger;
            var returnValue = defaultValue;
            if (
          /*false === this.isDevEnv &&*/ this.hasTeldFasRTUtils() &&
                this.isDevEnv !== true
            ) {
                try {
                    var r = window.TeldFasRTUtils.expression.execute(expression);
                    if (1 == r.state) {
                        returnValue = r.result;
                    }
                } catch (error) {
                    // console.error(error);
                }
            } else {
                console.debug("execExpression设计时");
            }
            return returnValue;
        },
        execServerAction(actionType, actionID, parameters) {
            // debugger;
            let returnValue = {};
            if (this.hasTeldFasRTUtils() && this.isDevEnv !== true) {
                let at = actionType;
                if (_.isNil(at)) {
                    let actionMetaData = TeldFasRTUtils.utils.getActionByID(actionID);
                    at = actionMetaData.ActionType;
                    // alert("参数actionType为空，为保证默认按2:ServerAction执行，");
                    console.log(
                        `参数actionType为空从框架获取Action信息,ActionType=${at}`,
                        actionMetaData
                    );
                }
                try {
                    let executeActionParam = {
                        ActionType: at, //FASConst.ACTIONTYPE_SERVER
                        ActionID: actionID,
                        Parameters: parameters,
                        JSScriptES5: "", //executeAction调用是结构必要字段，空就行
                    };
                    // debugger;
                    returnValue = TeldFasRTUtils.action.executeAction(executeActionParam);
                } catch (error) {
                    returnValue = this.fasBindContext[this.options.dataSource.DataSource];
                }
            } else {
                console.debug("execServerAction设计时");
            }
            return returnValue;
        },
        execRefreshVariable(variableName, mockData) {
            // debugger;
            if (this.hasTeldFasRTUtils() && this.isDevEnv !== true) {
                try {
                    window.TeldFasRTUtils.expression.refreshVar(variableName);
                } catch (error) {
                    this.fasBindContext[variableName] = mockData;
                }
            } else {
                console.debug("execRefreshVariable设计时");
            }
        }
    }
}

// import { observableDiff } from "./deep-diff.js";
const observableDiff = ()=>{}
export let mixinChangeTrack = {
    data() {
        this.ChangeTrackInstance = {};
        this.ChangeTrackResultSet = {};
        // return {};
        // return { ChangeTrackInstance: {} }
    },
    mounted() {
        _.set(window, "Widget.ChangeTrack", () => {
            return this.ChangeTrack();
        });
    },
    destroyed() {
        _.each(this.ChangeTrackInstance, (changeTrackConf, key) => {
            alert(`${key}.cancelWatch destroyed`);
            changeTrackConf.cancelWatch();
        });
    },
    methods: {
        TestChangeTrack() {
            this.ChangeTrack("LocalVars.vardata", (watchInfo) => {
                // debugger;
                alert('TestChangeTrack');
            })
        },
        _ChangeTrackKey(watchExp) {
            if (false === _.isString(watchExp)) {
                return;
            }
            let expOrFn = watchExp;

            if (_.startsWith(watchExp, "LocalVars.")) {
                expOrFn = `value.${watchExp}`;
            }
            return expOrFn;
        },
        ChangeTrackCore(watchExp, watchCallback, opts) {
            opts = opts || { deep: true }
            // debugger;
            if (false === _.isString(watchExp)) {
                return;
            }

            let expOrFn = this._ChangeTrackKey(watchExp);

            let changeTrackConf = this.ChangeTrackInstance[expOrFn];
            if (changeTrackConf) {
                changeTrackConf.cancelWatch();
            }
            let unWatch = this.$watch(expOrFn, (newVal, oldVal) => {
                // debugger;
                if (changeTrackConf && changeTrackConf.suspended) {
                    //暂停变更追踪
                    return;
                }
                this.WatchObservableDiff(changeTrackConf.previous || oldVal, newVal, changeTrackConf, watchCallback);
                // changeTrackConf.previous = { ...newVal };
                changeTrackConf.previous = _.cloneDeep(newVal);
            }, opts);
            let original = _.get(this, expOrFn);
            changeTrackConf = {
                suspended: false,
                watchExp,
                expOrFn,
                watchCallback: watchCallback,
                // original: { ...original },
                // previous: { ...original },
                original: _.cloneDeep(original),
                previous: _.cloneDeep(original),
                cancelWatch: () => {
                    unWatch();
                    delete this.ChangeTrackResultSet[changeTrackConf.watchExp];
                    delete this.ChangeTrackInstance[changeTrackConf.expOrFn];
                }
            }
            this.ChangeTrackInstance[expOrFn] = changeTrackConf;

            return changeTrackConf;
        },
        ChangeTrack(watchExp, watchCallback, prepUICallback, opts) {
            setTimeout(() => { this.ChangeTrackCore(watchExp, watchCallback, opts) }, 1000);
            if (prepUICallback) { prepUICallback() }
        },
        ChangeTrackReset(watchExp, prepUICallback) {
            let expOrFn = this._ChangeTrackKey(watchExp);
            let changeTrackConf = this.ChangeTrackInstance[expOrFn];
            let original = _.get(this, expOrFn);
            if (changeTrackConf) {
                // changeTrackConf.original = { ...original };
                // changeTrackConf.previous = { ...original };
                changeTrackConf.original = _.cloneDeep(original);
                changeTrackConf.previous = _.cloneDeep(original);
            }
            delete this.ChangeTrackResultSet[watchExp];
            if (prepUICallback) { prepUICallback() }
        },
        ChangeTrackCancel(watchExp) {
            let expOrFn = this._ChangeTrackKey(watchExp);
            let changeTrackConf = this.ChangeTrackInstance[expOrFn];
            if (changeTrackConf) {
                changeTrackConf.cancelWatch();
            }
        },
        WatchObservableDiff(oldVal, newVal, changeTrackConf, cb) {

            let resultSet = this.ChangeTrackResultSet[changeTrackConf.watchExp] || { changeSteps: [] };

            let returnValue = {
                cancelWatch: changeTrackConf.cancelWatch,
                data: {
                    original: changeTrackConf.original, oldVal, newVal,
                },
                originalDiff: { diffSet: {}, diffEdit: {} },
                diffSet: {}, diffSetOld: {}, diffEdit: {},
                changeSteps: resultSet.changeSteps
            };
            // debugger;
            // let diffSet = diff(oldVal, newVal);
            observableDiff(oldVal, newVal, (observer) => {
                let joinPath = _.join(observer.path, ".");
                // debugger;
                returnValue.diffEdit[joinPath] = { propPath: joinPath, kind: observer.kind, newVal: observer.rhs, oldVal: observer.lhs };
                _.set(returnValue.diffSet, joinPath, observer.rhs);
                _.set(returnValue.diffSetOld, joinPath, observer.lhs);
            });

            observableDiff(changeTrackConf.original, newVal, (observer) => {
                let joinPath = _.join(observer.path, ".");
                // debugger;
                returnValue.originalDiff.diffEdit[joinPath] = { propPath: joinPath, kind: observer.kind, newVal: observer.rhs, oldVal: observer.lhs };
                _.set(returnValue.originalDiff.diffSet, joinPath, observer.rhs);
            });

            returnValue.isRollback = _.isEmpty(returnValue.originalDiff.diffSet);

            resultSet.changeSteps.push({
                changeTime: Funcs.CurrDateTime(),
                diffSet: returnValue.diffSet,
                diffSetOld: returnValue.diffSetOld,
                diffEdit: returnValue.diffEdit
            });

            this.ChangeTrackResultSet[changeTrackConf.watchExp] = returnValue;
            if (false === _.isEmpty(returnValue.diffSet)) {
                cb(returnValue)
            }
            return returnValue;
        },
        ChangeTrackUndo(watchExp) {
            // debugger;
            let expOrFn = this._ChangeTrackKey(watchExp);
            let changeTrackConf = this.ChangeTrackInstance[expOrFn];
            changeTrackConf.suspended = true;
            //TODO:

            let undoChangeSteps = this.ChangeTrackResultSet[watchExp].changeSteps.pop();
            if (undoChangeSteps) {
                let oldVal = _.get(this, expOrFn);
                let newVal = { ...oldVal, ...undoChangeSteps.diffSetOld };
                _.set(this, expOrFn, newVal);
                this.$nextTick(() => {
                    changeTrackConf.suspended = false;
                });
            } else {
                changeTrackConf.suspended = false;
            }

        },
        ChangeTrackSuspend(watchExp) {
            let expOrFn = this._ChangeTrackKey(watchExp);
            let changeTrackConf = this.ChangeTrackInstance[expOrFn];
            changeTrackConf.suspended = true;
        },
        ChangeTrackPlay(watchExp) {
            let expOrFn = this._ChangeTrackKey(watchExp);
            let changeTrackConf = this.ChangeTrackInstance[expOrFn];
            changeTrackConf.suspended = false;
        },

    }
}